// ==========================================================================
// gin-sns自动生成控制器相关代码，只生成一次，按需修改,再次生成不会覆盖.
// date：2021-02-21 13:45:53 +0800 CST
// path: app/controller/module/article_api.go
// author：jon
// ==========================================================================
package module

import (
	"errors"
	"gin-sns/app/common/urls"
	"gin-sns/app/controller/api/cache"
	"gin-sns/app/controller/api/render"
	"gin-sns/app/ginframe/response"
	"gin-sns/app/ginframe/tools"
	"gin-sns/app/ginframe/utils/gconv"
	"gin-sns/app/model"
	"gin-sns/app/model/constants"
	articleModel "gin-sns/app/model/module/article"
	"gin-sns/app/service/collect"
	"gin-sns/app/service/module"
	"io/ioutil"
	"math/rand"
	"strings"

	"github.com/gin-gonic/gin"
	//"gin-sns/app/ginframe/utils/gconv"
)

var ArticleApi = newArticleApi()

func newArticleApi() *articleApi {
	return &articleApi{}
}

type articleApi struct {
}

//列表分页数据
func (c *articleApi) ListAjax(ctx *gin.Context) {
	req := new(articleModel.SelectPageReq)
	//获取参数
	if err := ctx.ShouldBind(req); err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).Log("article管理", req).WriteJsonExit()
		return
	}
	rows := make([]articleModel.Entity, 0)
	result, page, err := module.ArticleService.SelectListByPage(req)

	if err == nil && len(result) > 0 {
		rows = result
	}

	response.BuildTable(ctx, page.Total, rows).WriteJsonExit()
}

//新增页面保存
func (c *articleApi) AddSave(ctx *gin.Context) {
	req := new(articleModel.AddReq)
	//获取参数
	if err := ctx.ShouldBind(req); err != nil {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Add).SetMsg(err.Error()).Log("文章新增数据", req).WriteJsonExit()
		return
	}

	id, err := module.ArticleService.AddSave(req, ctx)

	if err != nil || id <= 0 {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Add).Log("文章新增数据", req).WriteJsonExit()
		return
	}
	response.SucessResp(ctx).SetData(id).Log("文章新增数据", req).WriteJsonExit()
}

//修改页面保存
func (c *articleApi) EditSave(ctx *gin.Context) {
	req := new(articleModel.EditReq)
	//获取参数
	if err := ctx.ShouldBind(req); err != nil {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Edit).SetMsg(err.Error()).Log("文章修改数据", req).WriteJsonExit()
		return
	}

	rs, err := module.ArticleService.EditSave(req, ctx)

	if err != nil || rs <= 0 {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Edit).Log("文章修改数据", req).WriteJsonExit()
		return
	}
	response.SucessResp(ctx).SetBtype(model.Buniss_Edit).Log("文章修改数据", req).WriteJsonExit()
}

//删除数据
func (c *articleApi) Remove(ctx *gin.Context) {
	req := new(model.RemoveReq)
	//获取参数
	if err := ctx.ShouldBind(req); err != nil {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Del).SetMsg(err.Error()).Log("文章删除数据", req).WriteJsonExit()
		return
	}

	rs := module.ArticleService.DeleteRecordByIds(req.Ids)

	if rs > 0 {
		response.SucessResp(ctx).SetBtype(model.Buniss_Del).Log("文章删除数据", req).WriteJsonExit()
	} else {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Del).Log("文章删除数据", req).WriteJsonExit()
	}
}

// 文章详情
func (c *articleApi) GetBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))

	article, err := module.ArticleService.SelectRecordById(articleId)

	if article == nil || err != nil || article.Status != model.ArticleStatusPublished {

		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
		return
	}
	module.ArticleService.IncrViewCount(articleId) // 增加浏览量
	response.SucessResp(ctx).SetData(article).WriteJsonExit()
	return
}

// 发表文章
func (c *articleApi) PostCreate(ctx *gin.Context) {
	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
	}

	req := new(articleModel.AddArticleRequest)
	//获取参数
	if err := ctx.ShouldBind(req); err != nil {
		response.ErrorResp(ctx).SetBtype(model.Buniss_Add).SetMsg(err.Error()).Log("文章添加数据", req).WriteJsonExit()
		return
	}

	tags := strings.Split(req.Tags, ",") //标签

	article, err := module.ArticleService.Publish(user.Id, req.Title, req.Summary, req.Content,
		constants.ContentTypeMarkdown, 0, tags, "", false)
	if err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
		return
	}
	response.SucessResp(ctx).SetData(article).Log("文章添加数据", req).WriteJsonExit()
	return
}

//RSS
func (c *articleApi) PostAdd(ctx *gin.Context) {
	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	articleReq := &articleModel.AddArticleRequest{}
	if err := ctx.ShouldBind(articleReq); err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
		return
	}

	articles := module.ArticleService.GetArticlesByUrl(articleReq.SourceUrl)
	if articles != nil && len(articles) > 0 {
		response.ErrorResp(ctx).SetMsg("话题「" + articleReq.SourceUrl + "」存在").WriteJsonExit()
		return
	}

	tags := strings.Split(articleReq.Tags, ",") //标签

	_, err := module.ArticleService.Publish(user.Id, articleReq.Title, articleReq.Summary,
		articleReq.Content, constants.ContentTypeMarkdown, 0, tags, articleReq.SourceUrl, true)
	if err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
		return
	}

	response.SucessResp(ctx).SetData(true).Log("文章新增数据", articleReq).WriteJsonExit()
	return
}

// 编辑文章
func (c *articleApi) PostEditBy(ctx *gin.Context) {

	articleId := gconv.Int64(ctx.Param("id"))
	tags := strings.Split(ctx.GetString("tags"), ",") //标签
	title := ctx.GetString("title")
	content := ctx.GetString("content")

	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	article, err := module.ArticleService.SelectRecordById(articleId)
	if article == nil || err != nil || article.Status == model.ArticleStatusDeleted {
		response.ErrorResp(ctx).SetMsg("文章不存在").WriteJsonExit()
		return
	}

	if article.UserId != user.Id {
		response.ErrorResp(ctx).SetMsg("无权限").WriteJsonExit()
		return
	}

	err2 := module.ArticleService.Edit(articleId, tags, title, content)
	if err2 != nil {
		response.ErrorResp(ctx).SetMsg(err2.Error()).WriteJsonExit()
		return
	}

	cache.ArticleTagCache.Invalidate(articleId)

	response.SucessResp(ctx).SetData(article.Id).WriteJsonExit() //todo  //"articleId", article.Id
	return
}

// 删除文章
func (c *articleApi) PostDeleteBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))

	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	article, _ := module.ArticleService.SelectRecordById(articleId)
	if article == nil || article.Status == model.ArticleStatusDeleted {
		response.ErrorResp(ctx).SetMsg("文章不存在").WriteJsonExit()
		return
	}

	if article.UserId != user.Id {
		response.ErrorResp(ctx).SetMsg("无权限").WriteJsonExit()
		return
	}

	do := module.ArticleService.DeleteRecordById(articleId)
	if !do {
		response.ErrorResp(ctx).SetMsg("failed").WriteJsonExit()
		return
	}
	response.SucessResp(ctx).WriteJsonExit()
	return
}

// 点赞文章 +1/-1
func (c *articleApi) PostLikeBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))
	like := ctx.GetInt("like")

	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	if like == 1 { //+1
		module.LikeService.ArticleLike(user.Id, articleId)
	} else { //cancel +1
		module.LikeService.CancelArticleLike(user.Id, articleId)
	}

	response.SucessResp(ctx).SetData(true).WriteJsonExit()
	return
}

// 收藏文章
func (c *articleApi) PostFavoriteBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))
	favor := ctx.GetInt("favor")

	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	if favor == 1 { //+1
		module.FavoriteService.AddArticleFavorite(user.Id, articleId)
	} else { //cancel +1
		module.FavoriteService.CancelArticleFavorite(user.Id, articleId)
	}

	response.SucessResp(ctx).WriteJsonExit()
	return
}

// 点赞文章 +1/-1
func (c *articleApi) PostRewardBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))
	reward := ctx.GetInt("reward")

	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	if reward == 1 { //+1
		module.RewardService.ArticleReward(user.Id, articleId)
	} else { //cancel +1
		module.RewardService.CancelArticleReward(user.Id, articleId)
	}

	response.SucessResp(ctx).SetData(true).WriteJsonExit()
	return
}

// 文章跳转链接
func (c *articleApi) GetRedirectBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))

	article, _ := module.ArticleService.SelectRecordById(articleId)
	if article == nil || article.Status != model.ArticleStatusPublished {
		response.ErrorResp(ctx).SetMsg("文章不存在").WriteJsonExit()
		return
	}
	//if article.Share && len(article.SourceUrl) > 0 {
	//	return tools.NewEmptyRspBuilder().Put("url", article.SourceUrl).JsonResult()
	//} else {
	//return tools.NewEmptyRspBuilder().Put("url", urls.ArticleUrl(articleId)).JsonResult()
	response.SucessResp(ctx).SetData(urls.ArticleUrl(articleId)).WriteJsonExit()
	//}
}

// 最近文章
func (c *articleApi) GetRecent(ctx *gin.Context) {
	articles := module.ArticleService.GetNewestArticles(10, 0)

	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(articles)).WriteJsonExit()
}

// 用户最近的文章
func (c *articleApi) GetUserRecent(ctx *gin.Context) {

	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	articles := module.ArticleService.GetUserNewestArticles(user.Id, 10, 0)

	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(articles)).WriteJsonExit()
}

// 用户文章列表
func (c *articleApi) GetUserArticles(ctx *gin.Context) {
	userId := gconv.Int64(ctx.Param("userId"))

	page := ctx.GetInt("page")

	articles := module.ArticleService.GetUserNewestArticles(userId, 20, page*20)

	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(articles)).WriteJsonExit()
}

// 文章列表
func (c *articleApi) GetArticles(ctx *gin.Context) {

	page := ctx.GetInt("page")
	size := ctx.GetInt("size")

	articles := module.ArticleService.GetNewestArticles(size, page*size)

	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(articles)).WriteJsonExit()

}

// 标签文章列表
func (c *articleApi) GetTagArticles(ctx *gin.Context) {
	cursor := ctx.GetInt64("cursor")
	tagId := ctx.GetInt64("tagId")

	articles, cursor := module.ArticleService.GetTagArticles(tagId, cursor)
	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(articles)).WriteJsonExit()
	return
}

// 分类文章列表
func (c *articleApi) GetCategoryArticles(ctx *gin.Context) {
	cursor := ctx.GetInt64("cursor")
	categoryId := ctx.GetInt64("categoryId")

	articles, cursor := module.ArticleService.GetCategoryArticles(categoryId, cursor)
	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(articles)).WriteJsonExit()
	return
}

// 用户最新的文章
func (c *articleApi) GetUserNewestBy(ctx *gin.Context) {
	user := module.UsertokenService.GetCurrent(ctx)
	if user == nil {
		response.ErrorResp(ctx).SetMsg(tools.ErrorNotLogin.Error()).WriteJsonExit()
		return
	}

	newestArticles := module.ArticleService.GetUserNewestArticles(user.Id, 10, 0)
	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(newestArticles)).WriteJsonExit()
	return
}

// 相关文章
func (c *articleApi) GetRelatedBy(ctx *gin.Context) {
	articleId := gconv.Int64(ctx.Param("id"))

	relatedArticles := module.ArticleService.GetRelatedArticles(articleId)
	response.SucessResp(ctx).SetData(render.BuildSimpleArticles(relatedArticles)).WriteJsonExit()
	return
}

// 推荐
func (c *articleApi) GetRecommend(ctx *gin.Context) {
	articles := cache.ArticleCache.GetRecommendArticles()
	if articles == nil || len(articles) == 0 {
		response.SucessResp(ctx).WriteJsonExit()
		return
	} else {
		dest := make([]articleModel.Entity, len(articles))
		perm := rand.Perm(len(articles))
		for i, v := range perm {
			dest[v] = articles[i]
		}
		end := 10
		if end > len(articles) {
			end = len(articles)
		}
		ret := dest[0:end]
		response.SucessResp(ctx).SetData(render.BuildSimpleArticles(ret)).WriteJsonExit()
		return
	}
}

//<<<
func (c *articleApi) GetUserList(ctx *gin.Context) {
	userName := ctx.GetString("user")

	page := ctx.GetInt("page") //1
	size := ctx.GetInt("size") // 20

	user := module.UserService.GetByUsername(userName)

	articles := module.ArticleService.GetUserNewestArticles(user.Id, size, page*size)

	response.SucessResp(ctx).SetData(render.BuildFeedArticles(articles)).WriteJsonExit()
	return

}

func (c *articleApi) GetCategoryList(ctx *gin.Context) {
	categoryName := ctx.GetString("category")
	page := ctx.GetInt("page") //1
	//size := ctx.GetInt("size") // 20

	if page == 0 {
		page = 1
	}

	if categoryName == "hot_collect" {

		if page == 1 {
			c.GetListHotCollect(ctx)
			return
		} else {
			response.ErrorResp(ctx).SetMsg("not found").WriteJsonExit()
			return
		}

	} else if categoryName == "hot" {

		if page == 1 {
			c.GetListHot(ctx)
			return
		} else {
			response.ErrorResp(ctx).SetMsg("not found").WriteJsonExit()
			return
		}

	} else if categoryName == "recommend" {

		if page == 1 {
			c.GetListRecommend(ctx)
			return
		} else {
			response.ErrorResp(ctx).SetMsg("not found").WriteJsonExit()
			return
		}

	} else if categoryName == "recent" {

		if page == 1 {
			c.GetListRecent(ctx)
			return
		} else {
			response.ErrorResp(ctx).SetMsg("not found").WriteJsonExit()
			return
		}

	} else {

		category := module.CategoryService.FindByName(categoryName)
		if category == nil {
			response.ErrorResp(ctx).SetMsg("分类「" + categoryName + "」不存在").WriteJsonExit()
		}

		articles, _ := module.ArticleService.GetCategoryArticles(category.Id, 0)

		response.SucessResp(ctx).SetData(render.BuildFeedArticles(articles)).WriteJsonExit()
		return
	}

}

func (c *articleApi) GetListRecommend(ctx *gin.Context) {
	articles := cache.ArticleCache.GetRecommendArticles()
	if articles == nil || len(articles) == 0 {
		response.SucessResp(ctx).WriteJsonExit()
		return
	} else {
		dest := make([]articleModel.Entity, len(articles))
		perm := rand.Perm(len(articles))
		for i, v := range perm {
			dest[v] = articles[i]
		}
		end := 40
		if end > len(articles) {
			end = len(articles)
		}
		ret := dest[0:end]
		response.SucessResp(ctx).SetData(render.BuildFeedArticles(ret)).WriteJsonExit()
		return
	}
}

func (c *articleApi) GetListRecent(ctx *gin.Context) {
	articles := module.ArticleService.GetNewestArticles(40, 0) //todo

	response.SucessResp(ctx).SetData(render.BuildFeedArticles(articles)).WriteJsonExit()
	return
}

func (c *articleApi) GetListHot(ctx *gin.Context) {
	articles := module.ArticleService.GetNewestArticles(40, 0) //todo

	response.SucessResp(ctx).SetData(render.BuildFeedArticles(articles)).WriteJsonExit()
	return
}

func (c *articleApi) GetListHotCollect(ctx *gin.Context) {
	articles := module.ArticleService.GetNewestArticles(40, 0) //todo

	response.SucessResp(ctx).SetData(render.BuildFeedArticles(articles)).WriteJsonExit()
	return
}

//>>>

// 微信采集发布接口
func (c *articleApi) PostWxpublish(ctx *gin.Context) {
	err := c.checkToken(ctx)
	if err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
	}
	article := &collect.WxArticle{}
	if err := ctx.ShouldBind(article); err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
		return
	}
	t, err := collect.NewWxbotApi().Publish(article)
	if err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
	}

	response.SucessResp(ctx).SetData(t.Id).WriteJsonExit() //"id", t.Id
	return
}

// 采集发布
func (c *articleApi) PostSpiderPublish(ctx *gin.Context) {
	err := c.checkToken(ctx)
	if err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
	}

	article := &collect.SpiderArticle{}
	if err := ctx.ShouldBind(article); err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
		return
	}

	articleId, err := collect.NewSpiderApi().Publish(article)
	if err != nil {
		response.ErrorResp(ctx).SetMsg(err.Error()).WriteJsonExit()
	}
	response.SucessResp(ctx).SetData(articleId).WriteJsonExit() //"id", articleId
	return
}

func (c *articleApi) checkToken(ctx *gin.Context) error {
	token := ctx.GetString("token")
	data, err := ioutil.ReadFile("./data/publish_token")
	if err != nil {
		return err
	}
	token2 := strings.TrimSpace(string(data))
	if token != token2 {
		return errors.New("token invalidate")
	}
	return nil
}
